package com.xykj.service.impl;

import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.gson.JsonArray;
import com.google.gson.JsonObject;
import com.google.gson.JsonParser;
import com.xykj.common.entry.SectorFundFlow;
import com.xykj.mapper.SectorFundFlowMapper;
import com.xykj.service.FCrawlerService;
import com.xykj.web.websocket.NewsWebSocketHandler;
import lombok.extern.slf4j.Slf4j;
import org.jsoup.Jsoup;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
/**
 * 爬取板块资金流向数据
 *
 */
@Slf4j
@Service
public class SectorFundCrawlerService implements FCrawlerService {

    @Autowired
    private RestTemplate restTemplate;

    @Autowired
    private SectorFundFlowMapper sectorFundFlowMapper;

    @Autowired
    private NewsWebSocketHandler webSocketHandler;

    // 基础URL，转义所有%为%%，保留时间戳占位符%s
    String baseApiUrl = "https://push2.eastmoney.com/api/qt/clist/" + "get?cb=jQuery112307727355755175558_%s&fid=f62&po=1&pz=50&pn=1&np=1&fltt=2&" + "invt=2&ut=8dec03ba335b81bf4ebdf7b29ec27d15&fs=m%%3A90+t%%3A2&fields=f12%%2Cf14%%2Cf2%%2Cf3" +
            "%%2Cf62%%2Cf184%%2Cf66%%2Cf69%%2Cf72%%2Cf75%%2Cf78%%2Cf81%%2Cf84%%2Cf87%%2Cf204%%2Cf205%%2Cf124%%2C" + "f1%%2Cf13";

    /**
     * 定时触发：通过 注解，设置每5分钟自动执行一次 crawl() 方法。
     * 构造请求：使用预定义的 baseApiUrl，动态插入当前时间戳，构造完整的API请求URL。
     * 发送请求：利用 Jsoup 库发送HTTP GET请求，获取返回的JSONP格式数据。
     * 解析JSONP：由于返回的是JSONP（JavaScript回调函数包裹的JSON），需要提取出中间的纯JSON字符串。
     * 解析JSON：使用 Gson 库解析JSON字符串，找到包含实际数据的 data 对象。
     * 解析业务数据：调用 parseSectorFundFlows 方法，进一步解析 data 对象中的 diff 数组，将其转换为 SectorFundFlow 对象列表。
     * 数据处理：筛选列表，只保留最新的100条记录。
     * 数据库操作：先查询并删除旧数据，再批量插入新数据。整个过程在 @Transactional 注解下，保证原子性。
     * 数据推送：通过 webSocketHandler.broadcast() 方法，将新数据推送给前端用户。
     * 异常处理：捕获可能出现的网络或解析异常，记录日志并返回执行状态。
     */
    @Override
    @Scheduled(cron = "0 * * * * ?")
//    @Scheduled(cron = "0 */5 * * * ?")
    @Transactional(rollbackFor = Exception.class)
    public boolean crawl() {
        try {
            log.info("开始爬取资金流向数据");
            Date startDate = new Date();
            // 动态生成时间戳
            long timestamp = System.currentTimeMillis();
            // 构建完整URL
            String apiUrl = String.format(baseApiUrl, timestamp);
            // 1. 发送HTTP请求获取JSONP数据
            String jsonpResponse = Jsoup.connect(apiUrl)
                    .ignoreContentType(true)
                    .execute()
                    .body();
            // 2. 提取JSON部分（去掉JSONP包装）
            String json = jsonpResponse.substring(
                    jsonpResponse.indexOf('(') + 1,
                    jsonpResponse.lastIndexOf(')')
            );
            // 3. 使用Gson解析JSON
            JsonObject jsonObject = JsonParser.parseString(json).getAsJsonObject();
            JsonObject data = jsonObject.getAsJsonObject("data");
            List<SectorFundFlow> sectorFundFlows = parseSectorFundFlows(data);
            // 4. 保存到数据库（保留前100条，可根据需求调整）
            int maxRecords = 100;
            List<SectorFundFlow> savedList = sectorFundFlows.subList(0, Math.min(maxRecords, sectorFundFlows.size()));
            // 获取现有记录ID
            List<Long> existingIds = sectorFundFlowMapper.selectExistingIds();
            // 批量删除旧数据
            if (!existingIds.isEmpty()) {
                sectorFundFlowMapper.batchDelete(existingIds);
            }
            // 批量插入新数据
            sectorFundFlowMapper.batchInsert(savedList);
            // WebSocket推送
            webSocketHandler.broadcast(savedList);
            log.info("成功保存 {} 条板块资金流向数据", savedList.size());
            return true;
        } catch (IOException e) {
            log.error("获取板块资金流向数据失败: {}", e.getMessage(), e);
        } catch (Exception e) {
            log.error("解析数据失败: {}", e.getMessage(),  e);
        }
        return false;
    }

    private List<SectorFundFlow> parseSectorFundFlows(JsonObject data) {
        List<SectorFundFlow> result = new ArrayList<>();
        LocalDateTime now = LocalDateTime.now();
        // 提取diff数组
        JsonArray diffArray = data.getAsJsonArray("diff");
        diffArray.forEach(element -> {
            JsonObject item = element.getAsJsonObject();
            SectorFundFlow flow = new SectorFundFlow();
            flow.setSectorName(item.get("f14").getAsString());
            // 修正点：使用ObjectMapper转换数值类型
            flow.setChangePercent(new BigDecimal(item.get("f3").getAsString()).negate());
            // 方向判断（根据实际业务逻辑）
            BigDecimal change = new BigDecimal(item.get("f3").getAsString()).negate();
            flow.setDirection(change.compareTo(BigDecimal.ZERO) >= 0 ? 1 : 0);
            flow.setDataTime(LocalDateTime.now());
            flow.setCreatedAt(now);
            flow.setUpdatedAt(now);
            result.add(flow);
        });
        return result;
    }
}